﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.SharePoint;
using Chaks.SharePoint.Docs.ILP.Utilities;
using System.Text;
using Microsoft.SharePoint.Administration;

namespace Chaks.SharePoint.Docs.ILP
{
    public static class ItemLevelPermissions
    {
        private const string JobResetRoleInheritanceName = "ILP_RoleInheritance";

        /// <summary>
        /// Enables the item level permissions.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="settings">The ILP settings.</param>
        public static void EnableItemLevelPermissions(this SPList list, ItemLevelPermissionSettings settings)
        {
            #region Method Body

            #region Check Event Reveivers

            if (String.IsNullOrEmpty(settings.EventReceiverAssembly) && String.IsNullOrEmpty(settings.EventReceiverClass))
            {
                settings.EventReceiverAssembly = "Chaks.SharePoint.Docs.ILP, Version=1.1.0.0, Culture=neutral, PublicKeyToken=5e4a77ec46c0cc45";

                settings.EventReceiverClass = "Chaks.SharePoint.Docs.ILP.EventReceivers.DocumentLibraryEventReceiver";
            }
            else if (String.IsNullOrEmpty(settings.EventReceiverAssembly) && !String.IsNullOrEmpty(settings.EventReceiverClass))
            {
                throw new SPException("Item-level Permission: Event Receiver Assembly or Event Receiver Class is empty");
            }
            else if (!String.IsNullOrEmpty(settings.EventReceiverAssembly) && String.IsNullOrEmpty(settings.EventReceiverClass))
            {
                throw new SPException("Item-level Permission: Event Receiver Assembly or Event Receiver Class is empty");
            }

            #endregion

            #region Enable ILP

            using (SPWeb spWeb=list.ParentWeb)
            {
                // Get the Id of the string 
                // Format - {GUID}
                string strListId = list.ID.ToString("B");

                Guid siteId = list.ParentWeb.Site.ID;

                SPEventReceiverDefinition itemUpdatedEvent = list.EventReceivers.Cast<SPEventReceiverDefinition>()
                                                                      .FirstOrDefault(listEvent => listEvent.Assembly == settings.EventReceiverAssembly
                                                                                    && listEvent.Type == SPEventReceiverType.ItemUpdated);

                SPEventReceiverDefinition itemAddedEvent = list.EventReceivers.Cast<SPEventReceiverDefinition>()
                                                                         .FirstOrDefault(listEvent => listEvent.Assembly == settings.EventReceiverAssembly
                                                                                       && listEvent.Type == SPEventReceiverType.ItemAdded);
                // If chosen to enable ILP
                if(settings.EnableItemLevelPermissions)
                {
                    //update the ILP item
                    UpdateILPItem(true,strListId,siteId,settings);

                    if (settings.ApplyToExistingItems)
                    {
                        //create the timer job to reset role inheritance on all items
                        ExecuteILPJob("break",list.ID,siteId,spWeb.ID);
                    }

                    // Add event receivers
                    if (itemAddedEvent == null)
                    {
                        list.EventReceivers.Add(SPEventReceiverType.ItemAdded, settings.EventReceiverAssembly, settings.EventReceiverClass);
                    }
                    if (itemUpdatedEvent == null)
                    {
                        list.EventReceivers.Add(SPEventReceiverType.ItemUpdated, settings.EventReceiverAssembly, settings.EventReceiverClass);
                    }
                }
                else // If chosen to disable ILP
                {
                    //update the ILP item
                    UpdateILPItem(false, strListId, siteId, settings);

                    // Remove event receivers
                    if (itemUpdatedEvent != null)
                    {
                        itemUpdatedEvent.Delete();
                    }
                    if (itemAddedEvent != null)
                    {
                        itemAddedEvent.Delete();
                    }
                    if (settings.ApplyToExistingItems)
                    {
                        //create the timer job to reset role inheritance on all items
                        ExecuteILPJob("reset", list.ID, siteId, spWeb.ID);
                    }
                }
            }

            #endregion

            #endregion
        }


        /// <summary>
        /// Updates the ILP item.
        /// </summary>
        /// <param name="update">if set to <c>true</c> [update].</param>
        /// <param name="listId">The list id.</param>
        /// <param name="siteId">The site id.</param>
        /// <param name="settings">The settings.</param>
        private static void UpdateILPItem(bool update,string listId,Guid siteId,ItemLevelPermissionSettings settings)
        {
            using(SPSite spSite=new SPSite(siteId))
            {
                using(SPWeb spWeb = spSite.RootWeb)
                {
                    SPList ilpList = spWeb.GetList("/Lists/ILPSet/");

                    string selectedPermissionSets = settings.DefaultGroups != null ? settings.DefaultGroups.CommaSeparatedGroups() : "NIL";

                    SPListItem ilpListItem;

                    if (spWeb.ILPExists(listId))
                    {
                        ilpListItem = spWeb.GetILPSetListItem(listId);
                    }
                    else
                    {
                        ilpListItem = ilpList.Items.Add();
                        ilpListItem["Title"] = listId;
                    }

                    if (settings.DefaultPermissionLevel!=null)
                    {
                        ilpListItem["PermissionLevel"] = update ? settings.DefaultPermissionLevel.Name : "NIL";
                    }
                    else
                    {
                        ilpListItem["PermissionLevel"] = "NIL";
                    }

                    ilpListItem["EnableILP"] = update ? "Yes" : "No";
                    if (!String.IsNullOrEmpty(selectedPermissionSets))
                    {
                        ilpListItem["Groups"] = update ? selectedPermissionSets : "NIL";
                    }
                    else
                    {
                        ilpListItem["Groups"] = "NIL";
                    }

                    ilpListItem.Update();       
                }
            }
            
        }

        /// <summary>
        /// Commas the separated groups.
        /// </summary>
        /// <param name="defaultGroups">The default groups.</param>
        /// <returns></returns>
        private static string CommaSeparatedGroups(this IList<SPGroup> defaultGroups)
        {
            if (defaultGroups.Count > 0)
            {
                StringBuilder commaSeparatedGroups = new StringBuilder();

                for (int i = 0; i < defaultGroups.Count; i++)
                {
                    if (i != (defaultGroups.Count - 1))
                    {
                        commaSeparatedGroups.Append(String.Format("{0},", defaultGroups[i].Name));
                    }
                    else
                    {
                        commaSeparatedGroups.Append(defaultGroups[i].Name);
                    }
                }

                return commaSeparatedGroups.ToString();
            }

            return "NIL";
        }

        /// <summary>
        /// Executes the ILP job.
        /// </summary>
        /// <param name="ilpJob">The ilp job.</param>
        /// <param name="listId">The list id.</param>
        /// <param name="siteId">The site id.</param>
        /// <param name="webId">The web id.</param>
        private static void ExecuteILPJob(string ilpJob,Guid listId,Guid siteId,Guid webId)
        {
            using (SPSite curSite = new SPSite(siteId))
            {
                //delete our job
                foreach (SPJobDefinition jobDefinition in curSite.WebApplication.JobDefinitions)
                {
                    if (jobDefinition.Name == JobResetRoleInheritanceName)
                    {
                        jobDefinition.Delete();
                    }
                }

                //install our job
                ILPRoleInheritanceJob resetItemRoleInheritanceJob = new ILPRoleInheritanceJob(JobResetRoleInheritanceName, curSite.WebApplication);

                SPMinuteSchedule jobSchedule = new SPMinuteSchedule();
                jobSchedule.BeginSecond = 0;
                jobSchedule.EndSecond = 30;
                jobSchedule.Interval = 1;

                resetItemRoleInheritanceJob.Name = JobResetRoleInheritanceName;
                resetItemRoleInheritanceJob.Properties.Add("ILP_Job", ilpJob);
                resetItemRoleInheritanceJob.Properties.Add("ILP_SiteId", siteId);
                resetItemRoleInheritanceJob.Properties.Add("ILP_WebId", webId);
                resetItemRoleInheritanceJob.Properties.Add("ILP_ListId", listId);

                resetItemRoleInheritanceJob.Schedule = jobSchedule;

                resetItemRoleInheritanceJob.Update();
            }
            //SPSecurity.RunWithElevatedPrivileges(delegate
            //                                         {
                                                         
            //                                         });
        }
    }
}
